﻿using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace WWLauncher.Util
{
    public class NetHelper : IDisposable
    {
        readonly HttpClient httpclient;
        const string Web = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0";

        public NetHelper()
        {
            UserAgent = Web; 
            var socketsHttpHandler = new SocketsHttpHandler()
            {
                //默认是None，即不压缩
                AutomaticDecompression = DecompressionMethods.GZip,
                UseProxy = false
            };
            httpclient = new HttpClient(socketsHttpHandler);
            httpclient.DefaultRequestHeaders.Add("User-Agent", this.UserAgent);
        }
        public NetHelper(DateTime? modifiedSince) : this()
        {
            ModifiedSince = modifiedSince;
        }
        #region 属性

        /// <summary>
        /// 设置UserAgent
        /// </summary>
        public string UserAgent { get; set; }

        /// <summary>
        /// 网页编码
        /// </summary>
        public string EncodingString
        {
            get;
            set;
        }
        public DateTime? ModifiedSince { get; set; }
        #endregion

        public Task<RemoteRes> GetAsync(string uri)
        {
            if (uri == null)
            {
                throw new ArgumentNullException(nameof(uri));
            }
            try
            {
                Uri _uri = new Uri(uri);
                return GetAsync(_uri, string.Concat("http://", _uri.Host));
            }
            catch (UriFormatException)
            {
                throw new UriFormatException(uri + "格式无效");
            }
            catch (Exception)
            {
                throw;
            }
        }

        public Task<RemoteRes> GetAsync(string uri, string referer)
        {
            Uri _uri = new Uri(uri);
            return GetAsync(_uri, referer);
        }
        public Task<RemoteRes> GetAsync(Uri uri)
        {
            return GetAsync(uri, string.Concat("http://", uri.Host));
        }
        public async Task<RemoteRes> GetAsync(Uri uri, string referer)
        {
            RemoteRes info = new RemoteRes();
            httpclient.DefaultRequestHeaders.Referrer = new Uri(referer);

            try
            {
                var response = await httpclient.GetAsync(uri).ConfigureAwait(false);
                if (response.StatusCode == HttpStatusCode.NotModified || response.StatusCode == HttpStatusCode.NoContent)
                {
                    info.StatusCode = response.StatusCode;
                    return info;
                }
                if (response.Content.Headers.LastModified.HasValue)
                    info.LastModified = response.Content.Headers.LastModified.Value.UtcDateTime;
                info.ContentType = response.Content.Headers.ContentType.ToString();
                info.StatusCode = response.StatusCode;
                info.Html = await response.Content.ReadAsStringAsync();

                return info;
            }
            catch (WebException we)
            {
                if (we.Response != null)
                {
                    info.StatusCode = ((HttpWebResponse)we.Response).StatusCode;
                }
                else
                {
                    info.StatusCode = HttpStatusCode.ServiceUnavailable;
                }
                if (info.StatusCode == HttpStatusCode.NotModified)
                {
                    info.Code = we.Message;
                }
                else
                {
                    info.Code = "错误：" + we.Message;
                }
            }
            catch (Exception ex)
            {
                info.Code = "错误：" + ex.Message;
                info.StatusCode = HttpStatusCode.InternalServerError;
            }
            return info;
        }

        /// <summary>
        /// 从网页上下载文件并保存到指定目录
        /// </summary>
        /// <param name="url">文件下载地址</param>
        /// <param name="directoryName">文件下载目录</param>
        /// <param name="fileName">不包括扩展名</param>
        /// <returns>下载是否成功</returns>
        public async Task<bool> DownloadFile(string url, string directoryName, string fileName)
        {
            bool sign = true;
            try
            {
                var httpclient = new HttpClient();
                HttpResponseMessage response = await httpclient.GetAsync(url);
                using (Stream stream = await response.Content.ReadAsStreamAsync())
                {
                    using (FileStream fileStream = new FileStream($"{directoryName}/{fileName}", FileMode.CreateNew))
                    {
                        byte[] buffer = new byte[512];
                        int length;
                        while ((length = await stream.ReadAsync(buffer, 0, buffer.Length)) != 0)
                        {
                            // 写入到文件
                            fileStream.Write(buffer, 0, length);
                        }
                    }
                }
            }
            catch (IOException)
            {
                //这里的异常捕获并不完善，请结合实际操作而定
                sign = false;
                Console.WriteLine("Downloader.DownloadFile：请检查文件名是否重复！");
            }
            return sign;
        }


        #region 获取编码
        /// <summary>
        /// 获取编码
        /// </summary>
        /// <param name="encodings"></param>
        /// <returns></returns>
        private static Encoding GetEncoding(string[] encodings)
        {
            try
            {
                if (encodings.Length == 1)
                {
                    if (encodings[0] == "nomatch")
                    {
                        return Encoding.GetEncoding("GBK");
                    }
                    else
                    {
                        return Encoding.GetEncoding(encodings[0]);
                    }
                }
                else
                {
                    string[] chinesecharsets = { "GB18030", "GBK", "GB2312", "Big5" };
                    var q = from x in chinesecharsets
                            where encodings.Contains(x.ToUpper())
                            select x;

                    if (q.Any() == false)
                    {
                        throw new NotSupportedException("没有中文编码，暂不采集。");
                    }
                    return Encoding.GetEncoding(q.First());
                }
            }
            catch
            {
                return null;
            }

        }

        #endregion

        public void Dispose()
        {
            httpclient.Dispose();
        }
    }

    public class RemoteRes
    {
        /// <summary>
        /// 返回信息的代码
        /// </summary>
        public string Code { get; set; }

        /// <summary>
        /// 信息
        /// </summary>
        public string Html { get; set; }

        /// <summary>
        /// 远程资源
        /// </summary>
        public byte[] Bytes { get; set; }

        /// <summary>
        /// 内容类型
        /// </summary>
        public string ContentType { get; set; }

        /// <summary>
        /// 状态代码
        /// </summary>
        public HttpStatusCode StatusCode { get; set; }

        public string Charset { get; set; }

        public DateTime LastModified { get; set; }
    }
}